// compile:
// apxs2 -c -i -a mod_embpy.c;/etc/init.d/apache2 restart

#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_log.h"
#include "http_protocol.h"
 
#include "ap_compat.h"

static int cnt=0;
 
static void register_hooks(apr_pool_t *p);
static int embpy_handler(request_rec *r);
char * cookies=NULL;


static void register_hooks(apr_pool_t *p)
{
  ap_hook_handler(embpy_handler, NULL, NULL, APR_HOOK_MIDDLE);
}
#define myname "mod_embpy"

char * my_errors[]=
  {
    "Unkonwn Error occured",
    "??",
    "File does not exist",
    "??",
    "??",
    "Python Compilation Error",
    "??",
    "??",   
    "??",
    "??",
    "??",
    "??",
    "??",
    NULL
  };

char *my_strerror(int e) {
  static char ebuf[100];
  //  if (e<sizeof(my_errors)/sizeof(char *))
  //  return(my_errors[e]);
  sprintf(ebuf,"err #%d",e);
  return(ebuf);
      
}

char * readfile(char *fn) {
  char *buf; int len;
  FILE *inf;
  inf=fopen(fn,"rb");
  if (!inf) {
    return(NULL);
  } 
  fseek(inf,0,SEEK_END);
  len=ftell(inf);
  fseek(inf,0,SEEK_SET);
  buf=(char *)malloc(len+1);
  if (!fread(buf,len,1,inf)) {
    return(NULL);
  }
  fclose(inf);
  buf[len]=0;
  return(buf);  
}
#define MAXBLEN 1000

void dumpfile(char *fn,char * color,request_rec *r) {
  char buf[MAXBLEN+2];
  char out[MAXBLEN+10];
  int p,op=0;
  FILE *inf;
  int l=1,len;
  sprintf(buf,"<hr><font face=\"courier new\" size=-2 color=\"%s\"><b>LISTING OF '%s'</b><br>", color,fn);
  ap_rputs(buf, r);

  inf=fopen(fn,"r");
  if (!inf) {
    ap_rputs("**** FILE MISSING ****<br>", r);
    ap_rputs("</font>", r);
    return;
  } 
  while (!feof(inf)) {
    if (!fgets(buf,MAXBLEN,inf))
      break;
    len=strlen(buf);
    sprintf(out,"%6d: ",l++);
    op=strlen(out);
    for (p=0;p<len;p++) {
      if (buf[p]=='<') {
	strcpy(&out[op],"&lt;");
	op+=4;
      } else if (buf[p]=='>') {
	strcpy(&out[op],"&gt;");
	op+=4;
      } else {
	out[op]=buf[p];
	op++;
      }
      out[op]=0;
    }
    ap_rputs(out, r);
  }
  ap_rputs("</font>", r);
  fclose(inf);
}

#define EMBPYHOME "/usr/local/src/embpy/html/"
char cookies2[100];
int iterate_func(void *req, const char *key, const char *value) {
    int stat;
    char *line;
    request_rec *r = (request_rec *)req;
    if (key == NULL || value == NULL || value[0] == '\0')
        return 1;
    
    line = apr_psprintf(r->pool, "%s => %s<br>", key, value);
    stat = ap_rputs(line, r);
    //Cookie => ppkcookie1=testcookie; ppkcookie2=testcookie
    /*    if (strcmp(key,"Cookie")==0) {
      cookies=malloc(strlen(value)+1);
      strcpy(cookies,value);
      sprintf(cookies2,"val: %s",value);
      ap_rputs("got cookies:", r);
      ap_rputs(cookies, r);
      ap_rputs("\n", r);
      }*/
    return 1;
}

static int embpy_handler(request_rec *r)
{
  FILE *inf;
  char *args,*referer,*useragent;
  char * buf,buf2[1500],*e,infname[200],oufname[200],htmlfname[200],err[100];
  int len,fail,dumpsrc=0;
  char *rbuf;
  cnt++;
  err[0]=0;
  if (strcmp(r->handler, "mod_embpy")) {
    return DECLINED;
  }
  r->content_type = "text/html"
    ap_send_http_header(r);
  if (r->args)
    args=r->args;
  else
    args="";
#if 1
  putenv("PYTHONPATH=/usr/local/src/embpy");

  //#else
  if (cookies) {
    //    free(cookies);
    cookies=NULL;
  }
  sprintf(cookies2,"-");
  sprintf(infname,"%s/%s",EMBPYHOME,r->path_info);
  sprintf(oufname,"%s/cache/%s.py",EMBPYHOME,r->path_info);
  sprintf(htmlfname,"%s/cache/%s.html",EMBPYHOME,r->path_info);

  cookies=apr_table_get(r->headers_in, "Cookie");
  referer=apr_table_get(r->headers_in, "Referer");
  useragent=apr_table_get(r->headers_in, "User-Agent");

  if (strcmp(r->method,"POST")==0) {
    int rc,bytes=0;
    args="";
    if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) != OK) {
      rbuf="";
    } else {
      if (ap_should_client_block(r)) {
	char argsbuffer[HUGE_STRING_LEN];
	int rsize, len_read, rpos=0;
	long length = r->remaining;
	rbuf=malloc(length+1);
	while ((len_read = ap_get_client_block(r, argsbuffer, sizeof(argsbuffer))) > 0) { 
	  if ((rpos + len_read) > length) {
	    rsize = length - rpos;
	  }
	  else {
	    rsize = len_read;
	  }
	  memcpy(&rbuf[rpos] + rpos, argsbuffer, rsize);
	  rpos += rsize;
	}
	//	bytes=ap_get_client_block(r, apu, length); 
	rbuf[length]=0;
      }
    }
    fail=embpy(infname,oufname,htmlfname,rbuf,cookies,r->connection->remote_ip,r->connection->remote_host,referer,useragent);
  } else {
    rbuf="";
    fail=embpy(infname,oufname,htmlfname,args,cookies,r->connection->remote_ip,r->connection->remote_host,referer,useragent);
  }
  if (!fail) {
    inf=fopen(htmlfname,"rb");
    if (!inf) {
      sprintf (err, "%s: Couldn't open file %s; %s\n", myname, htmlfname, strerror (errno));
      fail=1;
    } else {
      fseek(inf,0,SEEK_END);
      len=ftell(inf);
      fseek(inf,0,SEEK_SET);
      buf=(char *)malloc(len+1);
      if (!fread(buf,len,1,inf)) {
	sprintf (err, "%s: Couldn't read file %s; %s\n", myname, htmlfname, strerror (errno));
	fail=1;
      }
      fclose(inf);
      buf[len]=0;
    }
  } else {
    char *b,fn[100];
    sprintf(fn,"/tmp/embpy.%d.err",getpid());
    ap_rputs("<pre><Error log<br>", r);
    dumpfile(fn,"red",r);
    if (unlink(fn)) {
      //      sprintf (err, "%s: Couldn't unlink file %s; %s\n", myname, fn, strerror (errno));
      //ap_rputs(err, r);
    }
    sprintf (err, "%s: Could not compile file '%s' '%s'\n", myname, infname,my_strerror(fail) );
    dumpsrc=1;
  }


  if (fail) {
    ap_rputs(err, r);
  } else 
    //  if (!r->header_only)
    ap_rputs(buf, r);
#endif

  if (dumpsrc || strstr(args,"debug=1")!=NULL || strstr(rbuf,"debug=1")!=NULL ) {
    ap_rputs("<hr><pre>Source dump:<br>", r);
    dumpfile(infname,"green",r);
    dumpfile(oufname,"blue",r);
    dumpfile(htmlfname,"brown",r);
    ap_rputs("<hr><pre>X-Headers:<br>", r);
    apr_table_do(iterate_func, r, r->headers_in, NULL);
    e=getenv("PYTHONPATH");
    sprintf(buf2,"<hr><font size=-1>uri:%s fn:%s path:%s args:%s host:%s proto:%s method:%s conttype:%s contenc:%s pythonpath:%s handler:%s,the_requrest:%s, REQ:%s</font><hr>"
	    ,r->uri,r->filename,r->path_info,r->args,r->hostname,r->protocol,r->method
	    ,r->content_type,r->content_encoding,e,r->handler,r->the_request,rbuf
	    );
    ap_rputs(buf2, r);
  }
    sprintf(buf2,"remote ip: %s, name %s<hr>",r->connection->remote_ip,r->connection->remote_host);
    ap_rputs(buf2, r);
  {char b[1000];
    sprintf(b,"cookies:%s",cookies);
    ap_rputs(b, r);
  }
  return OK;
}
 
module AP_MODULE_DECLARE_DATA embpy_module =
  {
    STANDARD20_MODULE_STUFF,    /* stuff that needs to be declared in every 2.0 mod */
    NULL,                       /* create per-directory config structure            */
    NULL,                       /* merge per-directory config structures            */
    NULL,                       /* create per-server config structure               */
    NULL,                       /* merge per-server config structures               */
    NULL,                       /* command apr_table_t                              */
    register_hooks              /* register hooks                                   */
  };
